//--------------------------------------------------------------------------
// 
//  Copyright (c) Chili Software.  All rights reserved. 
// 
//  File: CachedQuery.cs
//
//  Description: Represents a cached query object.
// 
//--------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using Chili.Opf3.Query;
using Chili.Opf3.Storages;

namespace Chili.Opf3.Caching
{
	/// <summary>
	/// Represents a cached query object.
	/// </summary>
	internal sealed class CachedQuery
	{
		private IQuery _query;
		private IStorage _storage;
		private DateTime _validUntil;
		private DateTime _createdOn = DateTime.Now;
		private List<WeakReference> _objects = new List<WeakReference>();
		private Type _persistentType;

		/// <summary>
		/// Creates a new instance of the <see cref="CachedQuery">CachedQuery Class</see>.
		/// </summary>
		/// <param name="query">The query that is cached.</param>
		/// <param name="storage">The storage of the query.</param>
		/// <param name="validUntil">The time until the query is valid.</param>
		/// <param name="persistentType">The type of persistents in the query.</param>
		public CachedQuery(IQuery query, IStorage storage, DateTime validUntil, Type persistentType)
		{
			if (query == null)
				throw new ArgumentNullException("query");
			if (storage == null)
				throw new ArgumentNullException("storage");
			if (persistentType == null)
				throw new ArgumentNullException("persistentType");

			_query = query;
			_storage = storage;
			_validUntil = validUntil;
			_persistentType = persistentType;
		}

		/// <summary>
		/// Returns the query.
		/// </summary>
		public IQuery Query
		{
			get { return _query; }
		}

		/// <summary>
		/// Returns the storage where the query is executed on.
		/// </summary>
		public IStorage Storage
		{
			get { return _storage; }
		}

		/// <summary>
		/// Gets the persistents type. The type of the persistents held by this cached query.
		/// </summary>
		public Type PersistentsType
		{
			get { return _persistentType; }
		}

		/// <summary>
		/// Returns whether the cached persistent has expired.
		/// </summary>
		public bool Expired
		{
			get { return DateTime.Now > _validUntil; }
		}

		/// <summary>
		/// Gets or sets the date time until the item is valid.
		/// </summary>
		internal DateTime ValidUntil
		{
			get { return _validUntil; }
			set { _validUntil = value; }
		}

		/// <summary>
		/// Gets when the item was created.
		/// </summary>
		internal DateTime CreatedOn
		{
			get { return _createdOn; }
		}

		/// <summary>
		/// Adds a persistent object to the query.
		/// </summary>
		/// <param name="persistent">The persistent that has been added.</param>
		public void AddPersistent(CachedPersistent persistent)
		{
			_objects.Add(new WeakReference(persistent));
		}

		/// <summary>
		/// Tries to get the persistents for the query.
		/// </summary>
		/// <param name="persistents">The list of persistents that is returned.</param>
		/// <returns>False if the persistent couldn't get. Some might have expired.</returns>
		public bool TryGetPersistents<T>(out IList<T> persistents)
		{
			persistents = new List<T>();

			// If the query has expired return false.
			if (this.Expired)
				return false;

			// Check the persistents.
			foreach (WeakReference reference in _objects)
			{
				// Get the persistent.
				CachedPersistent persistent = (CachedPersistent)reference.Target;
				if (persistent == null || persistent.Expired)
				{
					// Clear the result and return false.
					persistents.Clear();
					return false;
				}

				// Get the inner persistent and add it to the list of persistents.
				persistents.Add((T)persistent.Persistent);
			}

			return true;
		}
	}
}
